/*
 * Copyright 2007-2009 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.paoding.rose.web.impl.module;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map.Entry;

import net.paoding.rose.web.ControllerErrorHandler;
import net.paoding.rose.web.ControllerInterceptor;
import net.paoding.rose.web.annotation.DefaultController;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.multipart.MultipartResolver;

/**
 * {@link Module}的实现
 * 
 * @author qieqie.wang@paoding.net
 * 
 */
public class ModuleBean implements Module {

	private static Log logger = LogFactory.getLog(ModuleBean.class);

	// 该模块的地址，由name自动计算而来
	private String path;
	private String[] pathElements;

	// 本模块的控制器对象(可能已经是做了AOP处理过的了)
	private LinkedHashMap<String, Object> controllers = new LinkedHashMap<String, Object>();

	// 控制器类(因为控制器对象可能已经作了AOP处理，为了方面这里就记录他的定义类，方便后面的annocation获取等操作)
	private LinkedHashMap<String, Class<?>> controllerClassess = new LinkedHashMap<String, Class<?>>();

	// 用于add方法加进来，最终==>到下面的interceptors
	private ArrayList<NamedControllerInterceptor> interceptorList;

	// 该模块的拦截器，调用get方法时候，由interceptorList.toArray进来,返回时保证非null
	private NamedControllerInterceptor[] interceptors;

	// 本模块的ErrorHanlder
	private ControllerErrorHandler errorHandler;

	// 默认的控制器，会先看看有没有@Path("")标注的或@DefaultController标注的，
	// 没有的话则按照候选方案看看有没有default,index,home,welcome的控制器，有的话就是它了
	private String defaultControllerPath;

	//
	private MultipartResolver multipartResolver;

	public ModuleBean() {
	}

	public ModuleBean(String path) {
		this.path = path;
		if (path.length() == 0) {
			this.pathElements = new String[0];
		} else {
			this.pathElements = path.substring(1).split("/|\\.");
		}
	}

	@Override
	public String getPath() {
		return path;
	}

	public String getName() {
		return path.length() == 0 ? "ROOT" : path;
	}

	@Override
	public String getDefaultControllerPath() {
		if (defaultControllerPath == null) {
			if (getController("") != null) {
				defaultControllerPath = "";
			} else {
				for (Entry<String, Class<?>> entry : controllerClassess
						.entrySet()) {
					if (entry.getValue().getAnnotation(DefaultController.class) != null) {
						defaultControllerPath = entry.getKey();
						logger.info("module '" + getName()
								+ "': found default controller '"
								+ defaultControllerPath + "'("
								+ entry.getValue().getName()
								+ ") by annotation @"
								+ DefaultController.class.getSimpleName());
					}
				}
				if (defaultControllerPath == null) {
					String[] candidates = { "/default", "/index", "/home",
							"/welcome", "/hello" };
					for (String candidate : candidates) {
						if (controllers.containsKey(candidate)) {
							defaultControllerPath = candidate;
							logger
									.info("module '"
											+ getName()
											+ "': found default controller '"
											+ defaultControllerPath
											+ "'("
											+ controllerClassess.getClass()
													.getName()
											+ ")  by sacnning controller by convention.");
							break;
						}
					}
				}
			}
			if (defaultControllerPath == null) {
				logger.warn("module '" + getName() + "': nout found"
						+ " a default controller by annotation"
						+ " or by convention.");
			} else {
				logger.info("module " + getName()
						+ "'s default controller: path="
						+ defaultControllerPath + "; by "
						+ getController(defaultControllerPath));
			}
		}
		return defaultControllerPath;
	}

	public void setDefaultControllerPath(String defaultControllerPath) {
		this.defaultControllerPath = defaultControllerPath;
	}

	@Override
	public Object getController(String controllerPath) {
		return controllers.get(controllerPath);
	}

	@Override
	public Class<?> getControllerClass(String controllerPath) {
		return controllerClassess.get(controllerPath);
	}

	public ModuleBean addController(String controllerPath,
			Class<?> controllerClass, Object controller) {
		this.controllers.put(controllerPath, controller);
		this.controllerClassess.put(controllerPath, controllerClass);
		return this;
	}

	public ModuleBean addControllerInterceptor(String name,
			ControllerInterceptor interceptor) {
		NamedControllerInterceptor namedInterceptor = new NamedControllerInterceptor(
				name, interceptor);
		return addNamedControllerInterceptor(namedInterceptor);
	}

	public ModuleBean addNamedControllerInterceptor(
			NamedControllerInterceptor namedInterceptor) {
		if (interceptorList == null) {
			interceptorList = new ArrayList<NamedControllerInterceptor>();
		}
		for (int i = 0; i < interceptorList.size(); i++) {
			if (namedInterceptor.getPriority() > interceptorList.get(i)
					.getPriority()) {
				this.interceptorList.add(i, namedInterceptor);
				return this;
			}
		}
		this.interceptorList.add(namedInterceptor);
		interceptors = null;
		return this;
	}

	@Override
	public NamedControllerInterceptor[] getInterceptors() {
		if (interceptors == null) {
			if (interceptorList == null) {
				interceptors = new NamedControllerInterceptor[0];
			} else {
				interceptors = interceptorList
						.toArray(new NamedControllerInterceptor[interceptorList
								.size()]);
			}
		}
		return interceptors;
	}

	@Override
	public List<String> getControllerPaths() {
		ArrayList<String> paths = new ArrayList<String>(controllers.size());
		paths.addAll(controllers.keySet());
		Collections.unmodifiableSet(controllers.keySet());
		return paths;
	}

	@Override
	public ControllerErrorHandler getErrorHandler() {
		return errorHandler;
	}

	public void setErrorHandler(ControllerErrorHandler errorHandler) {
		this.errorHandler = errorHandler;
	}

	@Override
	public MultipartResolver getMultipartResolver() {
		return multipartResolver;
	}

	public void setMultipartResolver(MultipartResolver multipartResolver) {
		this.multipartResolver = multipartResolver;
	}

	@Override
	public int compareTo(Module o) {
		if (this == o) {
			return 0;
		}
		if (path.length() == 0) {
			return 1;
		}
		ModuleBean that = ((ModuleBean) o);
		if (pathElements.length > that.pathElements.length) {
			return -1;
		} else if (pathElements.length < that.pathElements.length) {
			return 1;
		} else {
			for (int i = 0; i < pathElements.length; i++) {
				String pathElement = pathElements[i];
				String thatPathElement = that.pathElements[i];
				if (pathElement.startsWith(thatPathElement)) {
					return -1;
				}
				if (thatPathElement.startsWith(pathElement)) {
					return 1;
				}
				return pathElement.length() - thatPathElement.length();
			}
		}
		return 0;
	}
}
